use std::result;

use chrono::{Duration, NaiveDateTime, NaiveTime};
use rust_decimal::prelude::ToPrimitive;
use sea_orm::DatabaseConnection;
use sky_common::constant::{self, order};
use sky_pojo::vo::report::{OrderReportVO, SalesTop10ReportVO, TurnoverReportVO, UserReportVO};

use crate::mapper;

fn date_fill_to_end(mut begin: NaiveDateTime, end: NaiveDateTime) -> Vec<NaiveDateTime> {
    let mut date_list = Vec::<NaiveDateTime>::new();
    date_list.push(begin);

    while begin != end {
        begin = begin + Duration::days(1); // 日期加1天
        date_list.push(begin);
    }

    date_list
}

pub async fn get_turnover(
    db: &DatabaseConnection,
    mut begin: NaiveDateTime,
    end: NaiveDateTime,
) -> Result<TurnoverReportVO, String> {
    let date_list = date_fill_to_end(begin, end);

    let mut turnover_list = Vec::<f64>::new();

    for index in 0..date_list.len() {
        let begin_time = NaiveDateTime::new(
            date_list[index].into(),
            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
        );
        let end_time = NaiveDateTime::new(
            date_list[index].into(),
            NaiveTime::from_hms_opt(23, 59, 59).unwrap(),
        );

        // let turnover =
        //     .map_err(|e| e.to_string())
        //     .unwrap();

        let turnover = match mapper::report::ammount_days(db, begin_time, end_time).await {
            Ok(e) => match e {
                Some(d) => d,
                None => 0.0,
            },
            Err(e) => {
                return Err(e.to_string());
            }
        };

        turnover_list.push(turnover);
    }

    Ok(TurnoverReportVO {
        date_list,
        turnover_list,
    })
}

pub async fn get_user_statistics(
    db: &DatabaseConnection,
    begin: NaiveDateTime,
    end: NaiveDateTime,
) -> Result<UserReportVO, String> {
    let date_list = date_fill_to_end(begin, end);

    let mut new_user_list = Vec::<i64>::new();
    let mut total_user_list = Vec::<i64>::new();

    for index in 0..date_list.len() {
        let begin_time = NaiveDateTime::new(
            date_list[index].into(),
            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
        );
        let end_time = NaiveDateTime::new(
            date_list[index].into(),
            NaiveTime::from_hms_opt(23, 59, 59).unwrap(),
        );

        let new_user = match mapper::report::get_user_count(db, Some(begin), Some(end)).await {
            Ok(e) => match e {
                Some(d) => d,
                None => 0,
            },
            Err(e) => {
                return Err(e.to_string());
            }
        };

        let total_user = match mapper::report::get_user_count(db, None, Some(end)).await {
            Ok(e) => match e {
                Some(d) => d,
                None => 0,
            },
            Err(e) => {
                return Err(e.to_string());
            }
        };

        new_user_list.push(new_user);
        total_user_list.push(total_user);
    }

    Ok(UserReportVO {
        date_list,
        total_user_list,
        new_user_list,
    })
}

pub async fn get_order_statistics(
    db: &DatabaseConnection,
    begin: NaiveDateTime,
    end: NaiveDateTime,
) -> OrderReportVO {
    let date_list = date_fill_to_end(begin, end);

    let mut order_count_list = Vec::<i64>::new();
    let mut valid_order_count_list = Vec::<i64>::new();

    for index in 0..date_list.len() {
        let begin_time = NaiveDateTime::new(
            date_list[index].into(),
            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
        );
        let end_time = NaiveDateTime::new(
            date_list[index].into(),
            NaiveTime::from_hms_opt(23, 59, 59).unwrap(),
        );

        let order_count =
            match mapper::report::get_order_count(db, begin_time, end_time, None).await {
                Ok(e) => match e {
                    Some(d) => d,
                    None => 0,
                },
                Err(e) => 0,
            };

        let valid_order_count = match mapper::report::get_order_count(
            db,
            begin_time,
            end_time,
            Some(constant::order::COMPLETED),
        )
        .await
        {
            Ok(e) => match e {
                Some(d) => d,
                None => 0,
            },
            Err(_) => 0,
        };

        order_count_list.push(order_count);
        valid_order_count_list.push(valid_order_count);
    }

    let total_order_count = order_count_list.len();
    let valid_order_count = valid_order_count_list.len();

    let order_completion_rate = if total_order_count != 0 {
        valid_order_count as f64 / total_order_count as f64
    } else {
        0.0
    };

    OrderReportVO {
        date_list,
        order_count_list,
        valid_order_count_list,
        total_order_count,
        valid_order_count,
        order_completion_rate,
    }
}

pub async fn top_10(
    db: &DatabaseConnection,
    begin: NaiveDateTime,
    end: NaiveDateTime,
) -> Result<SalesTop10ReportVO, String> {
    let result = mapper::report::get_sales_top10(db, Some(begin), Some(end)).await;

    let goods_sales_dtolist = match result {
        Ok(vo) => vo,
        Err(e) => {
            let str = e.to_string();
            tracing::error!("query top_10 error: {}", str);
            return Err(str);
        }
    };

    let name_list = goods_sales_dtolist
        .iter()
        .map(|dto| dto.name.clone())
        .collect();

    let num_list = goods_sales_dtolist.iter().map(|dto| dto.number).collect();

    Ok(SalesTop10ReportVO {
        name_list,
        num_list,
    })
}
